﻿using System;
using System.Text.RegularExpressions;

namespace BoxSauce.AgencyToolkit.Net
{
    /// <summary>
    /// Represents a file or directory entry from an FTP listing
    /// </summary>
    /// <remarks>
    /// This class is used to parse the results from a detailed
    /// directory list from FTP. It supports most formats of
    /// </remarks>
    public class FtpFileInfo
    {
        private readonly string _filename;
        private readonly string _path;
        private readonly DirectoryEntryTypes _fileType;
        private readonly long _size;
        private readonly DateTime _fileDateTime;
        private readonly string _permission;

        #region "Properties"

        public string FullName
        {
            get
            {
                return Path + Filename;
            }
        }

        public string Filename
        {
            get
            {
                return _filename;
            }
        }

        public string Path
        {
            get
            {
                return _path;
            }
        }

        public DirectoryEntryTypes FileType
        {
            get
            {
                return _fileType;
            }
        }

        public long Size
        {
            get
            {
                return _size;
            }
        }

        public DateTime FileDateTime
        {
            get
            {
                return _fileDateTime;
            }
        }
      
        public string Permission
        {
            get
            {
                return _permission;
            }
        }

        public string Extension
        {
            get
            {
                int i = Filename.LastIndexOf(".", StringComparison.Ordinal);
                if (i >= 0 && i < (Filename.Length - 1))
                {
                    return Filename.Substring(i + 1);
                }
                
                return string.Empty;
            }
        }

        public string NameOnly
        {
            get
            {
                int i = Filename.LastIndexOf(".", StringComparison.Ordinal);
                if (i > 0)
                {
                    return Filename.Substring(0, i);
                }
                
                return Filename;
            }
        }

        #endregion

        /// <summary>
        /// Identifies entry as either File or Directory
        /// </summary>
        public enum DirectoryEntryTypes
        {
            File,
            Directory
        }

        /// <summary>
        /// Constructor taking a directory listing line and path
        /// </summary>
        /// <param name="line">The line returned from the detailed directory list</param>
        /// <param name="path">Path of the directory</param>
        /// <remarks></remarks>
        public FtpFileInfo(string line, string path)
        {
            //parse line
            var m = GetMatchingRegex(line);
            if (m == null)
            {
                //failed
                throw (new ApplicationException("Unable to parse line: " + line));
            }

            _filename = m.Groups["name"].Value;
            _path = path;

            Int64.TryParse(m.Groups["size"].Value, out _size);

            _permission = m.Groups["permission"].Value;
            var dir = m.Groups["dir"].Value;
            if (dir != "" && dir != "-")
            {
                _fileType = DirectoryEntryTypes.Directory;
            }
            else
            {
                _fileType = DirectoryEntryTypes.File;
            }

            try
            {
                _fileDateTime = DateTime.Parse(m.Groups["timestamp"].Value);
            }
            catch (Exception)
            {
                _fileDateTime = Convert.ToDateTime(null);
            }
        }

        private Match GetMatchingRegex(string line)
        {
            for (int i = 0; i <= ParseFormats.Length - 1; i++)
            {
                var rx = new Regex(ParseFormats[i]);
                var m = rx.Match(line);
                if (m.Success)
                {
                    return m;
                }
            }
            return null;
        }

        #region "Regular expressions for parsing LIST results"

        private static readonly string[] ParseFormats = new[] { 
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{4})\\s+(?<name>.+)", 
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{4})\\s+(?<name>.+)", 
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?<name>.+)", 
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?<name>.+)", 
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})(\\s+)(?<size>(\\d+))(\\s+)(?<ctbit>(\\w+\\s\\w+))(\\s+)(?<size2>(\\d+))\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{2}:\\d{2})\\s+(?<name>.+)", 
            "(?<timestamp>\\d{2}\\-\\d{2}\\-\\d{2}\\s+\\d{2}:\\d{2}[Aa|Pp][mM])\\s+(?<dir>\\<\\w+\\>){0,1}(?<size>\\d+){0,1}\\s+(?<name>.+)" };

        #endregion
    }

}
